// ------------------------------------------------------------------------------------------------
// File   : DX9_Bloom.cpp
// Date   : 2012-08-01
// Author : Weng xiao yi
// Descr. : Create an Bloom Effect of the frame buffer and cover the back buffer
//
// ------------------------------------------------------------------------------------------------

// ------------------------------------------------------------------------------------------------
// HEADERS
// ------------------------------------------------------------------------------------------------
#include "DX9Bloom.h"
// ------------------------------------------------------------------------------------------------
// IMPLEMENTATION
// ------------------------------------------------------------------------------------------------

DX9AE_Bloom::DX9AE_Bloom()
: DX9AfterEffect()
{
	SetAllResourceNull();
}

DX9AE_Bloom::~DX9AE_Bloom()
{
	Shutdown();
}

void DX9AE_Bloom::SetAllResourceNull()
{
	m_afFactor[eDX9_AE_Bloom_Param_SceneIntensity] = 0.6f;
	m_afFactor[eDX9_AE_Bloom_Param_GlowIntensity] = 0.4f;
	m_afFactor[eDX9_AE_Bloom_Param_HighlightThreshold] = 0.85f;
	m_afFactor[eDX9_AE_Bloom_Param_HighlightIntensity] = 0.6f;
	m_afFactor[eDX9_AE_Bloom_Param_BlurWidth] = 2.0f;

	m_DownSampleTexture = NULL;
	m_DownSampleSurface = NULL;
	m_BlurSampleTexture = NULL;
	m_BlurSampleSurface = NULL;
}

void DX9AE_Bloom::ReInit()
{
	SetAllResourceNull();

	HRESULT hr;

	IHRRenderer* RI = GetHREngine()->GetRenderer();
	LPDIRECT3DDEVICE9 pD3DDev = (LPDIRECT3DDEVICE9)(RI->GetRealDevice());

	hr = pD3DDev->CreateTexture( 
		GetHR3DConfig()->GetScreenWidth() / 2, 
		GetHR3DConfig()->GetScreenHeight() / 2,
		1, 
		D3DUSAGE_RENDERTARGET, 
		D3DFMT_A8R8G8B8, 
		D3DPOOL_DEFAULT, 
		&m_DownSampleTexture, 
		NULL ); 
	DX9Verify( SUCCEEDED(hr) );
	hr = m_DownSampleTexture->GetSurfaceLevel( 0, &m_DownSampleSurface );
	DX9Verify( SUCCEEDED(hr) );

	hr = pD3DDev->CreateTexture( 
		GetHR3DConfig()->GetScreenWidth() / 2, 
		GetHR3DConfig()->GetScreenHeight() / 2,
		1, 
		D3DUSAGE_RENDERTARGET, 
		D3DFMT_A8R8G8B8, 
		D3DPOOL_DEFAULT, 
		&m_BlurSampleTexture, 
		NULL ); 
	DX9Verify( SUCCEEDED(hr) );
	hr = m_BlurSampleTexture->GetSurfaceLevel( 0, &m_BlurSampleSurface );
	DX9Verify( SUCCEEDED(hr) );
}

void DX9AE_Bloom::OnDeviceLost()
{
	Shutdown();

	DX9AfterEffect::OnDeviceLost();
}

void DX9AE_Bloom::OnDeviceReset()
{
	DX9AfterEffect::OnDeviceReset();

	ReInit();
}

void DX9AE_Bloom::Shutdown()
{
	DX9_SAFE_RELEASE(m_DownSampleTexture);
	DX9_SAFE_RELEASE(m_DownSampleSurface);
	DX9_SAFE_RELEASE(m_BlurSampleTexture);
	DX9_SAFE_RELEASE(m_BlurSampleSurface);
}

void DX9AE_Bloom::Apply()
{	
	HRESULT hr;

	IHRRenderer* RI = GetHREngine()->GetRenderer();
	LPDIRECT3DDEVICE9 pD3DDev = (LPDIRECT3DDEVICE9)(RI->GetRealDevice());
	ICubeMaterial::MaterialList &Mat_list = ICubeMaterial::GetInstance().GetMaterialList();
	const ICubeMaterial::MaterialInfo &BloomMaterial_info = Mat_list[ICubeMaterial::eMaterial_posteffect];

	VECTOR4FLOAT vScreenResolution;
	vScreenResolution.x = GetHR3DConfig()->GetScreenWidth();
	vScreenResolution.y = GetHR3DConfig()->GetScreenHeight();
	vScreenResolution.z = 0.5f / GetHR3DConfig()->GetScreenWidth();
	vScreenResolution.w = 0.5f / GetHR3DConfig()->GetScreenHeight();
	VECTOR4FLOAT vSceneIntensity;
	vSceneIntensity.x = m_afFactor[eDX9_AE_Bloom_Param_SceneIntensity];
	VECTOR4FLOAT vGlowIntensity;
	vGlowIntensity.x = m_afFactor[eDX9_AE_Bloom_Param_GlowIntensity];
	VECTOR4FLOAT vHighlightThreshold;
	vHighlightThreshold.x = m_afFactor[eDX9_AE_Bloom_Param_HighlightThreshold];
	VECTOR4FLOAT vHighlightIntensity;
	vHighlightIntensity.x = m_afFactor[eDX9_AE_Bloom_Param_HighlightIntensity];
	VECTOR4FLOAT vBlurWidth;
	vBlurWidth.x = m_afFactor[eDX9_AE_Bloom_Param_BlurWidth];
	VECTOR4FLOAT vBlurDirectionH, vBlurDirectionV;
	vBlurDirectionH.x = 1;
	vBlurDirectionH.y = 0;
	vBlurDirectionV.x = 0;
	vBlurDirectionV.y = 1;

	GetSceneEffect()->StretchBackBufferToDecolor();

	LPDIRECT3DSURFACE9 pDefaultRT = NULL;
	LPDIRECT3DSURFACE9 pDefaultRTDepth = NULL;

	pD3DDev->GetRenderTarget( 0, &pDefaultRT );
	pD3DDev->GetDepthStencilSurface( &pDefaultRTDepth );
	DX9Verify(pDefaultRT);
	DX9Verify(pDefaultRTDepth);

	GetCubeMaterialRenderer()->PushMaterial( BloomMaterial_info.m_material, MM_Add );
	GetCubeMaterialRenderer()->ComputeMaterialPass();
	GetCubeMaterialRenderer()->OnePassPreRenderMaterial( 0 );


	///////////////////////////STEP 1 DOWNSAMPLE/////////////////////////
	pD3DDev->SetRenderTarget( 0, m_DownSampleSurface );
	pD3DDev->SetDepthStencilSurface( NULL );

	// get vertex shader for this material
	DX9VertexShaderManager::DX9VSFeatureAfterEffect oVSFeature1;
	oVSFeature1.stKey.ulShaderVer	  = 20;
	oVSFeature1.stKey.ulEffectId      = AE_TYPE_BLOOM_DOWNSAMPLE;
	oVSFeature1.stKey.ulEffectSubType = 0;
	DX9VertexShader* pVertexShader1 = DX9GetVertexShaderManager()->GetShader(&oVSFeature1);

	// get pixel shader for this material
	DX9PixelShaderManager::DX9PSFeatureAfterEffect oPSFeature1;
	oPSFeature1.stKey.ulShaderVer	  = 20;
	oPSFeature1.stKey.ulEffectId      = AE_TYPE_BLOOM_DOWNSAMPLE;
	oPSFeature1.stKey.ulEffectSubType = 0;
	DX9PixelShader* pPixelShader1 = DX9GetPixelShaderManager()->GetShader(&oPSFeature1);

	// use shaders
	hr = pD3DDev->SetVertexShader(pVertexShader1->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );
	hr = pD3DDev->SetPixelShader(pPixelShader1->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );

	pD3DDev->SetTexture( 0, GetSceneEffect()->GetDecolorTexture() );
	pD3DDev->SetTexture( 1, NULL );


	// upload constants
	if (pVertexShader1->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION))
		pVertexShader1->SetGlobalVector( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION, &vScreenResolution );
	if (pPixelShader1->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_HIGHLIGHTTHRESHOLD))
		pPixelShader1->SetGlobalVector( PS_GLOBAL_CONSTANT_HIGHLIGHTTHRESHOLD, &vHighlightThreshold );


	RI->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );


	///////////////////////////STEP 2 Blur H/////////////////////////
	pD3DDev->SetRenderTarget( 0, m_BlurSampleSurface );

	// get vertex shader for this material
	DX9VertexShaderManager::DX9VSFeatureAfterEffect oVSFeature2;
	oVSFeature2.stKey.ulShaderVer	  = 20;
	oVSFeature2.stKey.ulEffectId      = AE_TYPE_BLOOM_BLUR;
	oVSFeature2.stKey.ulEffectSubType = 0;
	DX9VertexShader* pVertexShader2 = DX9GetVertexShaderManager()->GetShader(&oVSFeature2);

	// get pixel shader for this material
	DX9PixelShaderManager::DX9PSFeatureAfterEffect oPSFeature2;
	oPSFeature2.stKey.ulShaderVer	  = 20;
	oPSFeature2.stKey.ulEffectId      = AE_TYPE_BLOOM_BLUR;
	oPSFeature2.stKey.ulEffectSubType = 0;
	DX9PixelShader* pPixelShader2 = DX9GetPixelShaderManager()->GetShader(&oPSFeature2);

	// use shaders
	hr = pD3DDev->SetVertexShader(pVertexShader2->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );
	hr = pD3DDev->SetPixelShader(pPixelShader2->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );

	pD3DDev->SetTexture( 0, m_DownSampleTexture );


	// upload constants
	if (pVertexShader2->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION))
		pVertexShader2->SetGlobalVector( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION, &vScreenResolution );
	if (pVertexShader2->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_BLURDIRECTION))
		pVertexShader2->SetGlobalVector( VS_GLOBAL_CONSTANT_BLURDIRECTION, &vBlurDirectionH );
	if (pVertexShader2->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_BLURWIDTH))
		pVertexShader2->SetGlobalVector( VS_GLOBAL_CONSTANT_BLURWIDTH, &vBlurWidth );
	

	RI->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

	///////////////////////////STEP 3 Blur V/////////////////////////
	pD3DDev->SetRenderTarget( 0, m_DownSampleSurface );

	pD3DDev->SetTexture( 0, m_BlurSampleTexture );


	// upload constants
	if (pVertexShader2->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_BLURDIRECTION))
		pVertexShader2->SetGlobalVector( VS_GLOBAL_CONSTANT_BLURDIRECTION, &vBlurDirectionV );

	RI->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

	///////////////////////////STEP 4 COMBINE ALL/////////////////////////
	pD3DDev->SetRenderTarget( 0, pDefaultRT );
	pD3DDev->SetDepthStencilSurface( pDefaultRTDepth );

	// get vertex shader for this material
	DX9VertexShaderManager::DX9VSFeatureAfterEffect oVSFeature3;
	oVSFeature3.stKey.ulShaderVer	  = 20;
	oVSFeature3.stKey.ulEffectId      = AE_TYPE_BLOOM_COMBINE;
	oVSFeature3.stKey.ulEffectSubType = 0;
	DX9VertexShader* pVertexShader3 = DX9GetVertexShaderManager()->GetShader(&oVSFeature3);

	// get pixel shader for this material
	DX9PixelShaderManager::DX9PSFeatureAfterEffect oPSFeature3;
	oPSFeature3.stKey.ulShaderVer	  = 20;
	oPSFeature3.stKey.ulEffectId      = AE_TYPE_BLOOM_COMBINE;
	oPSFeature3.stKey.ulEffectSubType = 0;
	DX9PixelShader* pPixelShader3 = DX9GetPixelShaderManager()->GetShader(&oPSFeature3);

	// use shaders
	hr = pD3DDev->SetVertexShader(pVertexShader3->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );
	hr = pD3DDev->SetPixelShader(pPixelShader3->GetShaderInterface());
	DX9Verify( SUCCEEDED(hr) );

	pD3DDev->SetTexture( 0, GetSceneEffect()->GetDecolorTexture() );
	pD3DDev->SetTexture( 1, m_DownSampleTexture );


	// upload constants
	if (pVertexShader3->IsGlobalConstPresent( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION))
		pVertexShader3->SetGlobalVector( VS_GLOBAL_CONSTANT_SCREEN_RESOLUTION, &vScreenResolution );
	if (pPixelShader3->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_SCENEINTENSITY))
		pPixelShader3->SetGlobalVector( PS_GLOBAL_CONSTANT_SCENEINTENSITY, &vSceneIntensity );
	if (pPixelShader3->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_GLOWINTENSITY))
		pPixelShader3->SetGlobalVector( PS_GLOBAL_CONSTANT_GLOWINTENSITY, &vGlowIntensity );
	if (pPixelShader3->IsGlobalConstPresent( PS_GLOBAL_CONSTANT_HIGHLIGHTINTENSITY))
		pPixelShader3->SetGlobalVector( PS_GLOBAL_CONSTANT_HIGHLIGHTINTENSITY, &vHighlightIntensity );

	RI->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );


	pD3DDev->SetVertexShader(NULL);
	pD3DDev->SetPixelShader(NULL);
	pD3DDev->SetTexture( 0, NULL );
	pD3DDev->SetTexture( 1, NULL );

	GetCubeMaterialRenderer()->OnePassPostRenderMaterial( 0 );
	GetCubeMaterialRenderer()->PopMaterial();

	DX9_SAFE_RELEASE(pDefaultRT);
	DX9_SAFE_RELEASE(pDefaultRTDepth);

}